Skip to content

crypto: BBS scheme for anonymous credentials with multiple presentations#1794

Open
epoberezkin wants to merge 16 commits into
stablefrom
ep/crypto-bbs
Open

crypto: BBS scheme for anonymous credentials with multiple presentations#1794
epoberezkin wants to merge 16 commits into
stablefrom
ep/crypto-bbs

Conversation

@epoberezkin

Copy link
Copy Markdown
Member

No description provided.

@epoberezkin epoberezkin requested a review from spaced4ndy as a code owner June 2, 2026 13:26

@simplex-chat-agent simplex-chat-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds Haskell FFI bindings to libbbs (BBS+ signatures over BLS12-381, SHA-256 suite). 6 newtypes + 6 API functions + tests. Submodules cbits/blst and cbits/libbbs (the latter as a SimpleX fork), with build wired through cabal at version 3.0 to use asm-sources for the BLST assembly. New commoncrypto flag swaps libbbs's getentropy for Apple's SecRandomCopyBytes to avoid iOS App Store rejection (ITMS-90338). Helper StrJSON added to Encoding.String to deduplicate ToJSON/FromJSON boilerplate. The FFI signatures match the C API documented in plans/2026-06-01-bbs-bindings.md, and withMessages correctly keeps each ByteString pinned via nested unsafeUseAsCStringLen for the duration of the C call.

Blocking

FromJSON skips length validation for BBSSecretKey, BBSPublicKey, BBSSignature, BBSProof. The module header claims "Any value parsed from untrusted input (StrEncoding / FromJSON) is length-validated". strDecode is — parseJSON isn't. StrJSON name is a newtype ... = StrJSON ByteString, so the derived FromJSON BBSSecretKey resolves strParseJSON at ByteString, runs raw base64urlP, and never touches the FixedBS/BBSProof instances. A 16-byte (or 0-byte, or 1000-byte) BBSSecretKey deserialised from JSON is then handed to withBS and bbsSign, which read the buffer assuming 32 bytes — heap OOB read in libbbs. See suggestion strjson-validate-fromjson. Fix is small: parameterise StrJSON over the wrapped type. No other code uses StrJSON.

Worth fixing

  • bbsProofGen allocates the output buffer from caller-controlled input without sanity checks. proofSz = 272 + 32 * (length msgs - length disclosedIdxs). If length disclosedIdxs > length msgs (or contains duplicates / out-of-range entries that libbbs counts literally), allocaBytes is called with a value smaller than what libbbs will write — and libbbs's bbs_proof_gen has no proof_len parameter, so the only thing protecting the buffer is libbbs's own internal validation. Exploitability depends on libbbs internals (submodule not checked out in this worktree, can't verify); regardless, a one-line guard before allocaBytes is cheap defense in depth.
  • bbsProofVerify accepts mismatched disclosedIdxs and disclosedMsgs. Parallel arrays of differing length get passed straight through to libbbs. Same defense-in-depth note: a precondition check (length disclosedIdxs == length disclosedMsgs) before the call is essentially free.
  • No JSON roundtrip test. All 8 BBS tests exercise the FFI directly with constructor values. The StrJSON bug above would have been caught by a single property test parseJSON . toJSON ≡ Right plus a "FromJSON rejects wrong-length input" negative test.
  • plans/2026-06-01-bbs-bindings.md is stale. It documents bbsSign :: BBSSecretKey -> BBSPublicKey -> BBSHeader -> ... and bbsKeyGen :: IO (BBSSecretKey, BBSPublicKey), but the code dropped the pk parameter from bbsSign and inverted the tuple order in bbsKeyGen (the latter now returns IO (Either String (BBSPublicKey, BBSSecretKey))). Either update the plan or drop it.

Notes (not changes)

  • BBSSecretKey derives Show showing the raw bytes. Matches the existing convention (PrivateKey a does the same in Simplex.Messaging.Crypto), so consistent; just noting it for awareness.
  • c_bbs_sha256_ciphersuite :: Ptr (Ptr BBS_Ciphersuite) followed by peek assumes the C symbol is a const pointer, not a const struct. If libbbs ever changes this to expose the struct directly, ciphersuite would silently dereference garbage. The current unsafePerformIO + NOINLINE pattern is fine for a pointer.
  • withMessages builds the parallel arrays via a list-reversing accumulator nested in N levels of unsafeUseAsCStringLen. For BBS+ message counts (typically 3-5) this is fine; not a concern.
  • libbbs and blst submodules pull from third-party C/asm into the build. Worth confirming that whoever audits this is happy with vendoring cbits/blst/src/server.c + cbits/blst/build/assembly.S into a library that previously had only cbits/sha512.c + cbits/sntrup761.c.

Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Crypto/BBS.hs
Comment thread src/Simplex/Messaging/Encoding/String.hs
Comment thread src/Simplex/Messaging/Encoding/String.hs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants